package com.test.mvcframework.servlet;

import com.test.mvcframework.interceptor.HandlerInterceptor;
import com.test.mvcframework.ioc.ApplicationContext;
import com.test.mvcframework.pojo.handler.*;
import com.test.mvcframework.pojo.view.TemplateViewResolver;
import com.test.mvcframework.pojo.view.ViewResolver;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author felix
 */
public class DispatcherServlet extends FrameworkServlet {

    private final Properties properties = new Properties();

    private final List<String> classNames = new ArrayList<>();

    private List<HandlerMapping> handlerMappings = new ArrayList<>();

    private List<HandlerAdapter> handlerAdapters;

    private List<ViewResolver> viewResolvers;



    @Override
    protected void initStrategies() {
        // 初始化handlerMappings
        initHandlerMappings(context);

        // 初始化handlerAdapter
        initHandlerAdapters(context);

        // 初始化ViewResolver
        initViewResolvers(context);
    }

    private void initViewResolvers(ApplicationContext context) {
        this.viewResolvers = getBeanListFromContext(context, ViewResolver.class);
    }

    private void initHandlerAdapters(ApplicationContext context) {
        this.handlerAdapters = getBeanListFromContext(context, HandlerAdapter.class);
    }

    private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = getBeanListFromContext(context, HandlerMapping.class);
    }

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        // 获取处理器映射器
        HandlerMapping handlerMapping = getHandlerMapping(request);
        if (handlerMapping == null) {
            response.getWriter().write("MVC: request not found: 404!");
            return;
        }
        HandlerExecutionChain chain = handlerMapping.getHandler();

        // 获取执行链
        boolean intercept = beforeService(request, response, chain);
        if (intercept) {
            return;
        }

        // 获取处理器适配器
        HandlerAdapter adapter = getHandlerAdapter((Handler) chain.getHandler());
        try {
            // 执行业务逻辑，获取响应
            Object result = adapter.handle(request, response, (MethodHandler) chain.getHandler());

            // 渲染视图
            processResult(result, request, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean beforeService(HttpServletRequest request, HttpServletResponse response,
            HandlerExecutionChain chain) throws IOException {
        for (HandlerInterceptor handlerInterceptor : chain.getInterceptorList()) {
            boolean intercept = handlerInterceptor.intercept(request, response, chain.getHandler());
            if (intercept) {
                return true;
            }
        }
        return false;
    }

    private void processResult(Object result, HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        if (result == null) {
            return;
        }
        ViewResolver viewResolver = getViewResolver(result.toString());
        viewResolver.render(request, response, result);
    }

    private ViewResolver getViewResolver(Object result) {
        if (result instanceof String) {
            for (ViewResolver viewResolver : this.viewResolvers) {
                if (viewResolver instanceof TemplateViewResolver) {
                    return viewResolver;
                }
            }
        }
        return null;
    }

    private HandlerAdapter getHandlerAdapter(Handler handler) {
        for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
            if (handlerAdapter.supports(handler)) {
                return handlerAdapter;
            }
        }
        return null;
    }

    private HandlerMapping getHandlerMapping(HttpServletRequest request) {
        for (HandlerMapping handlerMapping : handlerMappings) {
            if (handlerMapping.match(request)) {
                return handlerMapping;
            }
        }
        return null;
    }

    private Handler getHandler(HttpServletRequest request) {
        // TODO
        return null;
    }

    private <T> List<T> getBeanListFromContext(ApplicationContext context, Class<T> klass) {
        Map<String, T> classMap = context.getBeansOfType(klass);
        List<T> list = new ArrayList<>(classMap.size());
        classMap.forEach((key, value) -> {
            list.add(value);
        });
        return list;
    }
}
